import { Application, Container, Graphics, updateRenderGroupTransforms, Color} from "pixi.js";
import { Signal } from "./signal/Signal";
import { PixijsWorld } from "./entities/PixijsWorld";
import { TextEntity } from "./entities/TextEntity";
import { BaseEntity } from "./entities/BaseEntity";
import { EntityFactory } from "./entities/Factory";
import { PixijsEntity, ViewState } from "./entities/PixijsEntities";
import { CanvasRuler } from "./entities/CanvasRuler";
import { GroupEntity } from "./entities/GroupEntity";
import { PathEntity } from "./entities/PathEntity";
import { getControlPoints, getPerpendicularFoot, isPointInRectangle } from "./entities/PixijsTool";



const Zorder = {
    Top: 9999,
    Normal: 100,
    Back: -100
}

export enum RenderState {
    Null,
    BoxSelect,
    MoveCanvas
}


export class PixijsRender {

    appchange: Signal = new Signal();
    worldChange: Signal = new Signal();
    selectedChange: Signal = new Signal();
    alignEnableChange: Signal = new Signal();

    resRootUrl:string = "https://btri-dev.midea.com/web/hvsp-editor/"

    private __app: Application;
    private __world: PixijsWorld;
    private __ruler: CanvasRuler;
    private __graphicsControl: Graphics;
    private __viewRoot: Container;
    private __viewDirty: boolean = true;

    private __pointerDownPos: { x: number, y: number } = { x: 0, y: 0 };
    private __keyDown: boolean = false;
    private __moveOffset: [number, number] = [0, 0];
    private __preMovePos: [number, number] = [0, 0];
    private __movePos: [number, number] = [0, 0];
    private __selecteds: BaseEntity[] = []
    private __docListener: {type: string, listener: any}[] = [];

    tasks: (() => void)[] = []
    

    constructor() {
        this.__world = new PixijsWorld(this);
        this.onInit();
    }

    dispose(){
        if (this.__app) {
            this.__app.canvas.remove();
            this.__app.destroy();
        }
        this.__app = undefined;
    }

    onInit() {
        this.__world.onEntityAdded.add((entity: BaseEntity) => {
            let parent = entity.parent;
            while(parent && parent.isPrefab) {
                parent.isPrefab = false;
                parent.url = undefined;
                parent = parent.parent;
            }
            this.worldChange.dispatch();
            this.viewDirty = true;
        })

        this.__world.onEntityChanged.add((entity: BaseEntity, path: any, _value: any) => {
            if(path !== 'resize' || path !== 'locked' || path !== 'expanded' ||  path !== 'selected') {
                let parent = entity.parent;
                while(parent && parent.isPrefab) {
                    parent.isPrefab = false;
                    parent.url = undefined;
                    parent = parent.parent;
                }
            }
        })

        this.__world.onEntityRemoved.add((entity: BaseEntity) => {
            let parent = entity.parent;
            while(parent && parent.isPrefab) {
                parent.isPrefab = false;
                parent.url = undefined;
                parent = parent.parent;
            }
            this.worldChange.dispatch();
        })

        this.__world.onLoadSucceed.add(() => {
            this.worldChange.dispatch();
        })

     
    }

    get graphics() {
        return this.__graphicsControl;
    }

    get world() {
        return this.__world;
    }

    set viewDirty(dirty: boolean) {
        this.__viewDirty = dirty;
    }

    set app(c: Application) {
        if (this.__app !== c) {
            if (this.__app) {
                this.__app.canvas.remove();
                this.__app.destroy();
            }
            this.__app = c;

            for(let listener of this.__docListener) {
                document.removeEventListener(listener.type, listener.listener);
            }
            // 监听整个 canvas 的 pointermove 事件
            this.__docListener = [];

            let movelistener = (event:PointerEvent) => {
                this.onPointerMove(event);
            }

            let listener = (event:PointerEvent) => {
                if (event.button === 0) {
                    this.onPointerDown(event);
                    document.addEventListener('pointermove', movelistener);
                }
            }

            this.__app.canvas.addEventListener('pointerdown', listener);
           
           
            listener = (event:PointerEvent) => {
                this.onPointerUp(event);
                document.removeEventListener('pointermove', movelistener);
            }

            document.addEventListener('pointerup', listener);
            this.__docListener.push({type: 'pointerup', listener: listener});
            
            this.__app.canvas.addEventListener('wheel', (event) => {
                event.preventDefault(); // 防止默认滚动行为

                const scaleAmount = 0.05;
                const rect = this.app.canvas.getBoundingClientRect();
                const x = event.clientX - rect.left;
                const y = event.clientY - rect.top;

                
                let newScale = this.__viewRoot.scale.x + (event.deltaY > 0 ? -scaleAmount : scaleAmount);
                newScale = Math.max(0.05, Math.min(newScale, 5)); // 限制缩放范围
                this.__scaleCenter(newScale, {x, y});
                this.__viewDirty = true;
            });

            this.__app.ticker.add(() => {
               
                if (this.__viewDirty) {
                    updateRenderGroupTransforms(this.app.stage.renderGroup, true);
                    this.__graphicsControl.clear();
                    this.__moveCanves(); 
                }
           
                this.__viewSystem();
                if (this.__viewDirty) {
                    this.__transFormSystem();
                    this.__ruler.update();
                    this.__textSystem();
                }
                this.__selectedSystm();
                if(this.tasks.length > 0) {
                    let func = this.tasks.shift();
                    if(func) func();
                }
                this.__viewDirty = false;
            })

            this.__app.renderer.background.color = new Color([31 / 255, 31 / 255, 31 / 255])

            this.__viewRoot = new Container();
            this.__viewRoot.scale = 1.0;
            this.__app.stage.addChild(this.__viewRoot);
            this.__world.viewRoot = this.__viewRoot;

            this.__graphicsControl = new Graphics();
            this.__graphicsControl.zIndex = Zorder.Top;
            this.__app.stage.addChild(this.__graphicsControl);

            this.__ruler = new CanvasRuler(this);
            this.__ruler.zIndex = Zorder.Back;
            this.__app.stage.addChild(this.__ruler);

            this.viewDirty = true;
            this.appchange.dispatch();
        }

    }

    get app() {
        return this.__app;
    }

    get viewRoot() {
        return this.__viewRoot;
    }

    set cursor(v: string) {
        document.body.style.cursor = v;
    }

    private __moveCanves() {
       
        this.__viewRoot.position.x += this.__moveOffset[0];
        this.__viewRoot.position.y += this.__moveOffset[1];
        updateRenderGroupTransforms(this.app.stage.renderGroup, true);
        this.__moveOffset[0] = 0;
        this.__moveOffset[1] = 0;
    }

    private __scaleCenter(newScale: number, center: {x: number, y: number}){
        let inlocal = this.__viewRoot.toLocal(center);
        this.__viewRoot.scale.set(newScale);
        let inview = this.__viewRoot.toGlobal(inlocal);
        let offsetx = inview.x - center.x;
        let offsety = inview.y - center.y;
        this.__viewRoot.x -= offsetx;
        this.__viewRoot.y -= offsety;
    }

    onPointerDown(event: PointerEvent) {
        this.__viewDirty = true;


        const rect = this.app.canvas.getBoundingClientRect();
        const x = event.clientX - rect.left;
        const y = event.clientY - rect.top;

        this.__moveOffset[0] = 0;
        this.__moveOffset[1] = 0;
        this.__preMovePos[0] = x;
        this.__preMovePos[1] = y;
        this.__movePos[0] = x;
        this.__movePos[1] = y;

        this.__pointerDownPos.x = event.clientX;
        this.__pointerDownPos.y = event.clientY;

        this.__keyDown = true;
        this.__onClickEvent(event);
    }

    private __findGroup(entity: BaseEntity) {
        let current = entity.parent;
        let trueSelectEntity = entity;
        while (current) {
            if (current instanceof GroupEntity && !current.allowChildSelection) {
                trueSelectEntity = current;
            }
            current = current.parent;
        }
        return trueSelectEntity;
    }

    private __checkClickEntity(entity: BaseEntity, checkGroup: boolean = true){
        if (entity.view && !entity.locked) {
            if(!checkGroup && entity.className === 'GroupEntity') {
                return;
            }   
            if(entity.className === 'PathEntity') {
                let pathEntity = entity as PathEntity;
                let mousePos = {
                    x: this.__movePos[0],
                    y: this.__movePos[1]
                }
                let localPos = pathEntity.view.toLocal(mousePos);
                for(let i = 0; i < pathEntity.path.length; i++) {
                    let path = pathEntity.path[i];
                    for(let j = 0; j < path.length - 1; j++) {
                        let id1 = path[j];
                        let id2 = path[j + 1];
                        let point1 = pathEntity.points[id1];
                        let point2 = pathEntity.points[id2];
                      
                        //检测点到线段的垂足
                        let { x: x, y: y } = getPerpendicularFoot(localPos, point1, point2)
                        let distance = ((x - localPos.x) * (x - localPos.x) + (y - localPos.y) * (y - localPos.y));
                        let radius = pathEntity.lineWidth * 0.5;
                        //console.log(distance, radius*radius)
                        if(distance < radius*radius) {
                            return pathEntity;
                        }
                    }
                }
            } else {
                let points = getControlPoints(entity);
                if (isPointInRectangle(points[0], points[1], points[2], points[3], {x: this.__movePos[0], y: this.__movePos[1]})) {
                    let trueEntity = checkGroup ? this.__findGroup(entity) : entity;
                    return trueEntity;
                }
            } 
            
        }
    }

    private __onClickEvent(_: PointerEvent) {
        
        let entities = this.world.getAllUnlockedEntities();
        const lengths = entities.length;
       
        for (const entity of this.world.allEntities) {
            this.world.update(entity, "selected", false);
        }

        for (let i = lengths - 1; i >= 0; i--) {
            const entity = entities[i];
            if (entity.view) {
                let clicked = this.__checkClickEntity(entity, false)
                if (clicked) {
                    this.world.update(clicked, "selected", true)
                    return;
                }
            }
        }
        
    }

    onPointerMove(event: PointerEvent) {

        const rect = this.app.canvas.getBoundingClientRect();
        const x = event.clientX - rect.left;
        const y = event.clientY - rect.top;

        if( this.__keyDown ) {
            this.__moveOffset[0] += x - this.__preMovePos[0];
            this.__moveOffset[1] += y - this.__preMovePos[1];
        }  
        this.__movePos[0] = x;
        this.__movePos[1] = y;
        this.__preMovePos[0] = x;
        this.__preMovePos[1] = y;
    
        this.__viewDirty = true;
    }

    onPointerUp(_event: PointerEvent) {
        this.__keyDown = false;
    }

    private __textSystem() {
        for (const entity of this.world.allEntities) {
            if (entity.view) {
                if (entity instanceof TextEntity) {
                    entity.updateCSS();
                }
            }
        }
    }

    removeEntity(entity: BaseEntity) {
        this.__world.update(entity, "viewState", ViewState.WaitDestory);
        this.__viewDirty = true;
    }

    createEntity(name: string, classname: string, url: string = './img/tes.png'): BaseEntity {
        const entity = EntityFactory.createEntity<BaseEntity>(classname, this);
        this.world.add(entity);
        this.__world.update(entity, "name", name);
        this.__world.update(entity, "url", url);
        this.world.update(entity, "viewState", ViewState.WaitLoad);    
        return entity;
    }

    
   
    private __viewSystem() {
        for (const entity of this.world.allEntities) {
            if ((entity.viewState === ViewState.WaitLoad || entity.viewState === undefined)) {
                entity.loadAssets()
            }
            if (entity.viewState === ViewState.WaitDestory) {
                entity.viewState = ViewState.Destoryed;
                if (entity.view) entity.view.removeFromParent();
                entity.unloadAssets();
                this.world.remove(entity);
                this.__viewDirty = true;
            }

            if(entity instanceof PathEntity) {
                entity.drawPath();
            }

           
            if (entity.view) {
                if (entity.selected && entity.visible) {
                    this.__drawControl(entity);
                }
            }
            
        }
    }

    private __transFormSystem() {
        for (const entity of this.world.allEntities) {
            if (entity.view) {
                entity.view.angle = entity.rotation;
                //console.log(entity.position.x, entity.position.y)
                entity.view.position.set(entity.position.x, entity.position.y);
                entity.view.visible = entity.visible;
                entity.view.skew.x = entity.skew.x;
                entity.view.skew.y = entity.skew.y;
                entity.view.scale.x = entity.scale.x;
                entity.view.scale.y = entity.scale.y;

                //entity.view.pivot.set(entity.view.width * entity.anchor.x, entity.view.height * entity.anchor.y);
               

            }
        }
        
        //updateRenderGroupTransforms(this.app.stage.renderGroup, true);

        for (let i = this.world.allEntities.length - 1; i > -1; i--) {
            const entity = this.world.allEntities[i];
            if (entity.view) {
                if (entity instanceof GroupEntity) {
                    if (!entity.url && entity.children.length === 0) {
                        this.removeEntity(entity);
                    }
                }
            }
        }
    }

    private __selectedSystm() {
        let curSelecteds = []
        for (const entity of this.world.allEntities) {
            if (entity.selected) {
                curSelecteds.push(entity);
                if(entity.className === 'GroupEntity') {
                    (entity as GroupEntity).fixBound();
                }
            }
        }

        let same = true;
        if (curSelecteds.length === this.__selecteds.length) {
            for (let i = 0; i < this.__selecteds.length; i++) {
                if (curSelecteds[i] !== this.__selecteds[i])
                    same = false;
            }
        }
        else {
            same = false;
        }

        if (!same) {
            this.__selecteds = curSelecteds;
            this.selectedChange.dispatch(curSelecteds);
            this.__viewDirty = true;
        }
    }

    private __drawControl(entity: PixijsEntity) {
        let points = getControlPoints(entity)
        // 绘制四边形
        this.graphics.moveTo(points[0].x, points[0].y);
        for (let i = 0; i < 4; i++) {
            const point = points[i];
            this.graphics.lineTo(point.x, point.y);
        }

        this.graphics.lineTo(points[0].x, points[0].y); // 闭合四边形
        this.graphics.stroke({ width: 2, color: 0x00a1ff });
    }
}

